﻿Imports System.ComponentModel
Imports System.Collections.ObjectModel
Imports FuncClasses
Imports System.Threading.Tasks
Imports System.Windows.Threading

Public Class OrderViewModel
    Implements INotifyPropertyChanged

    Private db As IDatabase
    Private _dispatcher As Windows.Threading.Dispatcher
    Private _orders As ObservableCollection(Of OrderPreviewModel)
    Private _morders As ObservableCollection(Of OrderPreviewModel)
    Private _displayed As ObservableCollection(Of OrderPreviewModel)
    Private _startdate As Date
    Private _enddate As Date
    Private _years As ObservableCollection(Of String)
    Dim t2 As Task
    Public Event SelectedMonthsCompleted()
    Private _usr As User

    Public Sub New(loader As IDatabase, dispatcher As Windows.Threading.Dispatcher, usr As User)
        db = loader
        _dispatcher = dispatcher
        _years = New ObservableCollection(Of String)
        _years.Add(Date.Today.Year.ToString)
        If (Date.Today.Month > 10) Then
            _years.Add((Date.Today.Year + 1).ToString)
        End If
        _startdate = New Date(Date.Today.Year, Date.Today.Month, 1)
        _enddate = New Date(Date.Today.AddMonths(1).Year, Date.Today.AddMonths(1).Month, 1).AddDays(-1)
        _usr = usr
        t2 = Task.Factory.StartNew(AddressOf LoadAllOrders)
    End Sub

    Public Property AllOrders As ObservableCollection(Of OrderPreviewModel)
        Get
            Return _orders
        End Get
        Set(value As ObservableCollection(Of OrderPreviewModel))
            _orders = value
            NotifyPropertyChanged("AllOrders")
            Task.Factory.StartNew(Sub()
                                      GetOrdersInInterval()
                                  End Sub)
        End Set
    End Property

    Private Sub LoadAllOrders()
        Dim temp As ObservableCollection(Of OrderPreviewModel) = db.GetAllOrders(_usr)
        _dispatcher.BeginInvoke(Sub()
                                    AllOrders = temp
                                End Sub)
        Dim yearlist As New List(Of String)
        For Each o In temp
            If yearlist.Contains(New Datum(o.Date_).Jahr.ToString) = False Then
                yearlist.Add(New Datum(o.Date_).Jahr.ToString())
            End If
        Next
        If (Date.Today.Month > 10) AndAlso yearlist.Contains((Date.Today.Year + 1).ToString) = False Then
            yearlist.Add((Date.Today.Year + 1).ToString)
        End If
        If yearlist.Contains((Date.Today.Year).ToString) = False Then
            yearlist.Add((Date.Today.Year).ToString)
        End If
        yearlist.Sort()
        If yearlist.Count <> 0 Then
            _dispatcher.BeginInvoke(Sub()
                                        _years = New ObservableCollection(Of String)
                                        For Each item In yearlist
                                            _years.Add(item)
                                        Next
                                    End Sub)
        End If
        
        NotifyPropertyChanged("YearRange")
    End Sub

    Public Sub SetMonthlyInterval(year As Integer, month As Integer)
        IntervalStart = New Date(year, month, 1)
        IntervalEnd = New Date(_startdate.AddMonths(1).Year, _startdate.AddMonths(1).Month, 1).AddDays(-1)
        Task.Factory.StartNew(Sub()
                                  GetOrdersInInterval()
                              End Sub)
    End Sub

    Private Sub GetOrdersInInterval()
        Dim col As New ObservableCollection(Of OrderPreviewModel)
        Try
            Dim list = db.GetOrdersInInterval(_startdate, _enddate, _usr)
            Dim sortedcol = From orders In list Order By New Datum(orders.Date_).ToDate Ascending Group By New Datum(orders.Date_).ToDate Into sidegroup = Group Select (New With {.Order = sidegroup}.Order).OrderBy(Function(order) order.OrderID)
            For Each item In sortedcol
                For Each i In item
                    col.Add(i)
                Next
            Next
        Catch ex As Exception
            'AllOrders is empty
        End Try
        _dispatcher.BeginInvoke(Sub()
                                    DisplayedOrders = col
                                End Sub)
    End Sub

    Public Property IntervalStart As Date
        Get
            Return _startdate
        End Get
        Set(value As Date)
            _startdate = value
            NotifyPropertyChanged("IntervalStart")
        End Set
    End Property

    Public Property IntervalEnd As Date
        Get
            Return _enddate
        End Get
        Set(value As Date)
            _enddate = value
            NotifyPropertyChanged("IntervalStart")
        End Set
    End Property

    Public Sub Refresh()
        If t2.IsCompleted Then
            t2 = Task.Factory.StartNew(AddressOf LoadAllOrders)
        End If
    End Sub

    Public Function OrdersByCustomer(ByVal customerid As String) As ObservableCollection(Of OrderPreviewModel)
        Dim temp As New ObservableCollection(Of OrderPreviewModel)
        Dim mutex As New System.Threading.Mutex
        Parallel.ForEach(db.GetOrdersByCustomer(customerid, _usr), Sub(item As OrderPreviewModel)
                                                                       mutex.WaitOne()
                                                                       temp.Add(item)
                                                                       mutex.ReleaseMutex()
                                                                   End Sub)
        Return temp
    End Function

    Protected Sub NotifyPropertyChanged(info As [String])
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
    End Sub

    Public ReadOnly Property YearRange As ObservableCollection(Of String)
        Get
            Return _years
        End Get
    End Property

    Public Property DisplayedOrders As ObservableCollection(Of OrderPreviewModel)
        Get
            Return _displayed
        End Get
        Set(value As ObservableCollection(Of OrderPreviewModel))
            _displayed = value
            NotifyPropertyChanged("DisplayedOrders")
        End Set
    End Property

    Public Sub SaveOrder(order As Order)
        db.SaveOrUpdateOrder(order, _usr)
        If _usr.CanWriteOrder Then
            Dim prev As New OrderPreviewModel With {.OrderTyp = order.DokumentArt, .Value = order.TotalValue, .OrderID = order.OrderID, .Date_ = order.Datum.ToString, .CustomerName = order.Customer.DisplayName}
            If AllOrders.Contains(prev) Then
                AllOrders(AllOrders.IndexOf(prev)) = prev
            Else
                AllOrders.Add(prev)
            End If
            Task.Factory.StartNew(AddressOf GetOrdersInInterval)
        End If
    End Sub
    Public Event PropertyChanged(sender As Object, e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged

#Region "Sorting Things"
    Private _iddirection As ListSortDirection = ListSortDirection.Ascending
    Private _dateDirection As ListSortDirection = ListSortDirection.Ascending
    Private _typeDirection As ListSortDirection = ListSortDirection.Descending
    Private _customerDirection As ListSortDirection = ListSortDirection.Descending
    Private _valueDirection As ListSortDirection = ListSortDirection.Descending

    Public Sub SortByID()
        If _iddirection = ListSortDirection.Ascending Then
            LinqToCol(From item In DisplayedOrders Order By item.OrderID Descending)
            _iddirection = ListSortDirection.Descending
        Else
            LinqToCol(From item In DisplayedOrders Order By item.OrderID Ascending)
            _iddirection = ListSortDirection.Ascending
        End If
    End Sub

    Public Sub SortByDate()
        If _dateDirection = ListSortDirection.Ascending Then
            LinqToCol(From item In DisplayedOrders Order By New Datum(item.Date_).ToDate Descending)
            _dateDirection = ListSortDirection.Descending
        Else
            LinqToCol(From item In DisplayedOrders Order By New Datum(item.Date_).ToDate Ascending)
            _dateDirection = ListSortDirection.Ascending
        End If
    End Sub

    Public Sub SortByType()
        If _typeDirection = ListSortDirection.Ascending Then
            LinqToCol(From item In DisplayedOrders Order By item.OrderTyp Descending)
            _typeDirection = ListSortDirection.Descending
        Else
            LinqToCol(From item In DisplayedOrders Order By item.OrderTyp Ascending)
            _typeDirection = ListSortDirection.Ascending
        End If
    End Sub

    Public Sub SortByCustomer()
        If _customerDirection = ListSortDirection.Ascending Then
            LinqToCol(From item In DisplayedOrders Order By item.CustomerName Descending)
            _customerDirection = ListSortDirection.Descending
        Else
            LinqToCol(From item In DisplayedOrders Order By item.CustomerName Ascending)
            _customerDirection = ListSortDirection.Ascending
        End If
    End Sub

    Public Sub SortByValue()
        If _valueDirection = ListSortDirection.Ascending Then
            LinqToCol(From item In DisplayedOrders Order By item.Value Descending)
            _valueDirection = ListSortDirection.Descending
        Else
            LinqToCol(From item In DisplayedOrders Order By item.Value Ascending)
            _valueDirection = ListSortDirection.Ascending
        End If
    End Sub

    Private Sub LinqToCol(sortedCo As System.Linq.IOrderedEnumerable(Of OrderPreviewModel))
        Dim output As New ObservableCollection(Of OrderPreviewModel)
        For Each item In sortedCo
            output.Add(item)
        Next
        DisplayedOrders = output
    End Sub
#End Region
End Class
